ES6介绍

阮一峰es6文档地址: https://es6.ruanyifeng.com/

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了也叫ECMAScript 2015。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言

(一) let 命令和const命令

知识点:

  1. let的用法类似于var,用于变量的声明

  2. 使用let就会产生块级作用域,let命令只在块级作用域内(也就是大括号内)有效

  3. let在同一作用域内只能声明一次, 不能重复声明

  4. let和const不存在变量提升

详细例子:

1. let命令

<script>
    //1.let块级作用域
    {
        var a = 100;
        let b = 200;
    }
    console.log('a=',a);
    // console.log('b=',b); // b只在{}内有效

    for(let i=0;i<5;i++) {

    }
    // console.log(i); i只在{}内有效  
</script>

2. const命令

<script>
    // const用来声明常量,不能改变(不能重新赋值)
    const PI = 3.1415926535;
    // PI = 100;

    // const 声明变量, 如果是变量是对象
    // 对象不能重新赋值, 但是属性可用修改
    const obj = {
        name: '张三',
        age: 100
    }
    // obj = {name:'lisi'}; // 常量不能重新赋值
    obj.a = '李四';  
</script>
3.不能重复声明
<script>
    let a = 100;
    let a = 200; // 会报错,a已经声明,不能重复声明 
</script>

4.var、let、const 区别(背诵)

var 关键字的特点:
    -	变量(预解析)提升,可以在声明的前面使用
    - 同一作用域内可以多次声明同一个变量(即便这种方式不建议这样去写)
    - 能让它形成作用域的只有函数

let:声明变量的关键字
    - 没有变量提升,只能在声明之后使用
    - 同一作用域内只能声明一次
    - 你声明的变量的作用域仅限于最近的花括号{} 
    
const:只能用来声明常量,该常量一旦声明其值就不能改变(let的唯一区别)
	  - 没有变量提升,只能在声明之后使用
    - 同一作用域内只能声明一次
    - 你声明的变量的作用域仅限于最近的花括号{}-const声明的变量: 不允许重新赋值,引用数据类型可以添加或修改属性

(二) 变量的解构赋值

知识点:

  1. 解构: 结构分解, 从一个整体的变量里分解出一部分来使用

  2. 数组解构

  3. 对象解构

  4. 函数参数解构和默认值

// 1.数组和对象的解构
<script> 
    //数组解构
    let [a,b,c] = [1,2,3];
    console.log('a:',a); //值为1

    let [p1,p2] = [{name: '张三'},{name: '李四'}];
    console.log('P1:',p1); // [{name: '张三'}

    //对象解构
    let obj = {
        username:'张三',
        age: 100,
        addr: '广东'
    }
    let {username,age} = obj;
    console.log('username:',username); // 张三
    console.log('age:',age); // 100  
</script>

// 2.在函数中使用解构

<script>
    function say({username,age}) {
        let str = '他叫'+username+',他的年龄是'+age;
        console.log(str);    
    }

    let obj = {username:'李四',age:100}
    say(obj); 
</script>

// 3.默认值
<script>
  let  {} =  ;
    function say({username='张三',age=100}) {
        let str = '他叫'+username+',他的年龄是'+age;
        console.log(str);    
    }

    let obj = {username:'李四',age:100}
    // say(obj);  
    say({});
</script> 

<script>
    // data的默认值为{}, 若没有默认值{},当不传参数时会报错
    function say(data={}) {
	 console.log(data.username);
    } 
    say({username: '张三'}); 
    say(); 
</script>

(三) 模板字符串

<!DOCTYPE html>
<html lang="en"> 
<body> 
    <script>
        let username = '老张';
        let age = 100;
        // let  str = '他叫'+username+',他老了';
        let str = `他叫${username},他${age}`;

        let htmlStr = `<ul>
                            <li>${username}</li>
                            <li>${age}</li> 
                        </ul>`;
 
    </script>
</body>
</html>

(四) 对象的扩展

知识点:

  1. 属性和方法的简洁表示法

  2. 变量做属性名

  3. 合并对象

详细例子:

// 1.属性和方法的简洁表示法
<script>
    let username = 'zhagnsan';
    let age = 100;

    // let obj = {
    //     username:username,
    //     age: age
    // }
    let obj = {
        username,
        age,
        say() {
            console.log(this.username);
        }
    }
    console.log(obj); 
</script>

// 2.变量做属性名
<script>
    let a = 'username';
    let b = 'age'; 
    let obj = {
        [a]: 'xxx',
        [b]: 'yyy'
    } 
    console.log(obj);
</script>

// 3.合并对象
<script>
    let obj1 = {username:'zs'};
    let obj2 = {age:100}
    let obj = Object.assign(obj1,obj2);
    console.log('obj',obj);

    let a = {
        username: '张三',
        age: 100
    }
    let b = {
        username: '李四',
        age: 200,
        addr: 'gd'
    }
    let c = Object.assign(a,b);
    console.log('c',c); // {username:'李四',age:200,addr:'gd'}
</script>

(五) 函数的扩展: 箭头函数

知识点

  1. 箭头函数的常见表达方式

  2. 箭头函数的this指向:

    • 专业说法: 由于箭头函数不绑定this, 它会捕获其所在上下文的this值, 作为自己的this值

    • 大白话:拿别人的this当成是自己的, 表面现象就是箭头函数外面this是什么, 它的this就是什么

  3. 箭头函数不能做构造函数, 箭头函数的arguments对象不可用

详细例子

// 1. 箭头函数常见的表达方式
<script>
    function add(a,b) {
        return a+b;
    }
    // 1.箭头函数写法1
    let add = (a,b)=> {
        return a+b;
    }

    // 2.箭头的简写方式,函数体只有一行的时候,可以简写成
    let add2 = (a,b)=>a+b;

    // 3.当参数只有一个的时候,可以简写成:
    let s1 = (num)=> {
        return num*num;
    }
    // 简写
    let s2 = num => num*num;

    let list = [1,2,3];
    let newList1 = list.map((item)=> {
        return item*2;
    }); 
    // 简写
    let newList2 = list.map(item=>item*2); 
</script>

// 2. 箭头函数的this指向
<script>
    let obj = {
        say() {
            console.log('say中的this',this);
            setTimeout(function() {
                console.log('普通函数,',this);
            },1000);

            setTimeout(()=>{
                console.log('箭头函数',this);
            },2000)
        }
    }
    obj.say(); 
</script>

<script>
	// 箭头函数不能做构造函数
  // MadeCat是自定义构造函数,用来创建对象的
    function MadeCat(name) {
        this.name = name;
    }
    let cat = new MadeCat('小黑');

    // 箭头函数不能做构造函数
    let  MadeCat2 = (name) => {
        this.name = name;
    }
    let cat2 = new MadeCat2('小花');
	
	// arguments对象
    function add(){
       console.log('arguments',arguments);  
       console.log('类型',Array.isArray(arguments)); 
    } 
    add(1,2,3,4); 

    let add2 = () => {
        // 箭头函数不存在arguments对象,所以会报错
        console.log('arguments',arguments); 
    }
    add2();
</script>

(六) 数组的扩展

知识点:

  1. Array.from() // 将伪数组(类数组)变成真数组

  2. find() // 找到了就返回符合条件的成员, 找不着就返回undefined

  3. findIndex() // 找到了就返回符合条件的成员的下标, 找不着就返回undefined

  4. includes() // 判断数组是否包含某个成员, 只能对数组成员是基本数据类型的数组使用

  5. some() // 判断数组是否包含某个成员

  6. keys() // 遍历键, 了解

  7. values() // 遍历值, 了解

  8. entries() // 遍历键值对, 了解

详细例子

// 1.Array.from
<script>
    function add() { 
        let arg =  Array.from(arguments);
        console.log(arg);
        console.log(Array.isArray(arg));
    }
    add(1,2,3); 
</script>

// 2.find
<script>
    let list = [{ username: 'zs', age: 21 }, { username: 'lisi', age: 20 }, { username: 'ww', age: 22 }, { username: 'lisi', age: 100 }];
    let obj = list.find(item => item.username === 'lisan');
    console.log('obj', obj);
</script>

// 3.findIndex 
<script>
    let list = [{ username: 'zs', age: 21 }, { username: 'lisi', age: 20 }, { username: 'ww', age: 22 }, { username: 'lisi', age: 100 }]; 
    // let index = list.findIndex(function(item) {
    //     return item.username === 'ww';
    // })
    let index = list.findIndex(item => item.username === 'ww'); 
    console.log('index',index); 
</script> 

(七) 扩展运算符 ...

知识点:

  1. 在对象中使用
  2. 在数组中使用
  3. 在函数中使用

详细例子:

<script>
    let obj1 = {a:2,b:3,c:4};
    let obj2 = {a:10,b:20,x:4}; 
    // 1.合并两个对象, 属性相同, 后者覆盖前者
    let obj = {
        ...obj1,
        ...obj2
    }
    console.log('obj',obj); 
</script>

<script>
    // 2.合并两个数组
    let arr1 = [1,2,3];
    let arr2 = [3,4,5]
    let arr = [
        ...arr1,
        ...arr2
    ]
    console.log('arr',arr); 
</script>

// 3.在函数中使用
<script>
    function add(num1,num2,...num3) {
        console.log('num1:',num1); // 10
        console.log('num2:',num2); // 20
        console.log('num3:',num3); // [30,40,50]
    }
    add(10,20,30,40,50); 
</script>

(八) Promise(背诵)

知识点:

  1. promise定义

  2. promise使用

  3. promise的用途

(1) 什么是promise

  1. promise中文意思承诺

  2. promise有三种状态:

    • pending 正在进行中

    • resolved 成功

    • rejected 失败

  3. promise状态一旦改变,就无法再次改变状态,这也是它名字 promise-承诺 的由来,一个promise对象只能改变一次

(2) promise的使用步骤:

  1. 创建promise对象
  2. 存储成功或失败的数据
  3. 获取promise对象的数据
// 1.创建一个简单的promise对象
<script>
    let isSuccess = false;
    // 1.1创建promise对象,接收一个函数作为参数
    let promiseObj = new Promise((resolve,reject)=>{
        // resolve()用来处理成功的情况
        // reject()处理失败的情况
        if (isSuccess) {
            resolve({
                code: 666,
                msg: '成功了'
            });
        } else {
            reject({
                code: 500,
                msg: '失败了'
            })
        }   
    });

    // 1.2读取promise对象的值
    promiseObj.then(res=> {
        console.log('res',res);
    }).catch(error=> {
        console.log('error',error);
    })
</script>

// 2.例子: axios.get()和axios.post()方法返回的都是一个Promise实例
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script>
  var obj = axios.get('http://huruqing.cn:3003/category/all');
  console.log(obj instanceof Promise); 
  // 因为obj是一个Promise的实例对象, 所以可以用.then()来获取数据
  obj.then(res=> {
    console.log(res);
  }).catch(err=> {
    console.log(err);
  })
</script>

(3) promise的用途

promise是异步编程的一种解决方案, 是为了解决回调地狱的问题(核心在于async await)

// 3.1回调地狱
<script>
    let isSuccess = true;
    let promiseObj = new Promise((resolve, reject) => {
         axios.get('').then(res=>{
             axios.get('').then(res=> {
                 axios.get('').then(res=> {
                     resolve(res.data);
                 })
             })
         })
    })
</script>
   
// 3.2 async await可以把异步变同步
<script>
    let isSuccess = true;
    let promiseObj = new Promise((resolve, reject) => {
        setTimeout(() => {
            if (isSuccess) {
                resolve({msg:'成功'});
            } else {
                reject({msg:'成功'});
            }
        }, 5000) 
    })

    // .then().catch()是异步的
    // console.log(1);
    // promiseObj.then(res=> {
    //     console.log(2); 
    // }).catch(err=> {
    //     console.log(err);
    // })
    // console.log(3);

    // async await是同步的
    console.log(1);
    async function getData() {
       // 可以对promise对象使用await,让异步变同步 
       console.log(2);
       let res = await promiseObj;
       console.log('res',res);
       console.log(3);
    }
    getData();
		console.log(4);
		
</script>    
    
    
// 3.3解决回调地狱
<script>
    let isSuccess = true;
    let promiseObj1 = new Promise((resolve, reject) => {
         setTimeout(()=>{
             resolve({msg:'success'})
         },2000)
    })
    let promiseObj2 = new Promise((resolve, reject) => {
         setTimeout(()=>{
             resolve({msg:'success'})
         },4000)
    })
    let promiseObj3 = new Promise((resolve, reject) => {
         setTimeout(()=>{
             resolve({msg:'success'})
         },6000)
    })

    // 回调地狱
    promiseObj1.then(res=> {
        promiseObj2.then(res=> {
            promiseObj3.then(res=> {
                console.log(res);
            })
        })
    })

    // 使用async await把异步变同步
    async function getData() {
        let res1 = await promiseObj1;
        let res2 = await promiseObj2;
        let res3 = await promiseObj3;
        console.log('res3',res3); 
    }
</script>
编程题: 根据提供的三个接口, 编写代码,找到广东分校web02班何秀英,并打印她的年龄
http://huruqing.cn:3009/getSchool  无需参数
http://huruqing.cn:3009/getClass  // 需要schoolId
http://huruqing.cn:3009/getStudent  // 需要参数classId
// 使用回调的方式解决
<script>
axios.get('http://huruqing.cn:3009/getSchool').then(res => {
    // console.log(res.data);
    // 查找广东分校
    let school = res.data.find(item => item.schoolName === '广东分校');
    // 获取schoolId
    let {
        schoolId
    } = school;
    // 根据schoolId获取班级列表
    axios.get(`http://huruqing.cn:3009/getClass?schoolId=${schoolId}`).then(res => {
        // 查找何秀英所在班级
        let classObj = res.data.find(item => item.className === 'web02');
        let {
            classId
        } = classObj;
        // 根据classId查找学生列表
        axios.get(`http://huruqing.cn:3009/getStudent?classId=${classId}`).then(res => {
            // console.log(res.data);
            let student = res.data.find(item => item.studentName === '何秀英');
            console.log('何秀英的年龄是', student.age);
        });
    })
});
  
</script>


// 使用async await把异步变同步
<script>
  // 封装请求函数
  function getData(url) {
  let promiseObj = new Promise((resolve, reject) => {
    axios.get(url).then(res => {
      resolve(res.data);
    }).catch(err => {
      reject(err);
    });
  })
  return promiseObj;
}


async function getList() {
  let url1 = 'http://huruqing.cn:3009/getSchool';
  let schoolList = await getData(url1);
  // 查找广东分校
  let school = schoolList.find(item=>item.schoolName==='广东分校');
  // 查找广东分校下的所有班级
  let url2 = `http://huruqing.cn:3009/getClass?schoolId=${school.schoolId}`;
  let classList = await getData(url2);
  // 查找web02班
  let classObj = classList.find(item=>item.className==='web02');
  // 根据班级id查找学生
  let url3 = `http://huruqing.cn:3009/getStudent?classId=${classObj.classId}`
  let studentList = await getData(url3);
  let student = studentList.find(item=>item.studentName==='何秀英');
  console.log('何秀英的年龄是',student.age); 
} 
getList(); 
</script>

(九) ES6 模块系统

在html中使用模块

<script type="module"></script>

(1) 常用模块化规范:

  1. commonjs规范 nodejs遵守commonjs规范

  2. AMD规范 reqire.js遵守AMD规范

  3. CMD规范 sea.js遵守CMD规范(玉伯, 淘宝)

  4. ES6规范

(2) ES6模块导出和导入:

1. 导出和导入方式(一)
  • export // 导出
  • import {xx} from xxx // 导出名称是什么, 导入名称也是什么
// 导出 demo.js
export let username = '张三';
export let age = 100;

// 导入 demo.html
 <script type="module">
   import {username,age} from './demo.js';
   console.log(username,age);
 </script>
2. 导出和导入方式(二)
  • export default // 默认导出
  • import xx from xx // 导入,可以使用任意名称接收默认导出的变量
// 导出 demo.js
// var obj = {
// 	username: '张三',
// 	age:100
// }
// export default obj;


// 可以写成
export default  {
	username: '张三',
	age:100
}
// 导入 demo.html
 <script type="module">
   import obj from './demo.js';
   console.log(obj);
 </script>
3. 重命名
  • import {aa as xx} from xxx // 导入之后重命名
  • import * as xx from xxx // 导入之后重命名
// 导出 demo.js
export let username = '张三';
export let age = 100;
// 导入1 demo.html
 <script type="module">
   import {username as uname,age} from './demo.js';
   console.log(uname);
   console.log(age);
 </script>
// 导入2
 <script type="module">
   import * as obj from './demo.js';
   console.log(obj); 
 </script>

(十) class

es5没有class的概念

  1. 声明一个类
  2. 类继承
// es6的类, 用来创建对象
class Person{
   // 构造器(其实就是es5里的构造函数)
   constructor(nation) {
    this.nation = nation;
    this.type = '人类';
   }

   say() {
       console.log(`这是一个${this.nation}`);
   }

   sing() {
       console.log('人类会唱歌');
   }
   
}


// 定义一个女人的类
class Woman extends Person{
    constructor(nation) {
        // 调用父类构造器
        super(nation);
        this.sex = '女人';
    }
}

var w = new Woman('中国');
console.log('国籍',w.nation);
console.log('类别',w.type);
w.sing();

(十一) 新类型(了解)

  1. map

  2. set

  3. symble

<script> 
  	// Map数据结构
    let map = new Map([['name','张三'],['age',100]]);
    let name = map.get('name');
    let age = map.get('age');
    console.log('name=',name);
    console.log('age=',age); 
</script>

<script>
  	// Set数据结构
    let arr = [1,43,5,2,76,5,1];
    let set = new Set(arr);
    // 可以使用...,把它变成数组,可以用来去重
    let list = [...set];
    console.log('list',list);
</script>

<script>
    // symble是基本数据类型,使用symble创建的数据具有唯一性
    let s1 = Symbol('aa');
    let s2 = Symbol('aa');
    console.log(s1 === s2);  // false 
</script>